
#include <utils/transformer.h>
#include <scene/lodnode.h>

ceTransformer::ceTransformer()
{
  Clear ();
}

void ceTransformer::Clear()
{
  for (std::vector<Trans>::iterator it = _transformations.begin();
       it != _transformations.end();
       ++it)
    {
      Trans& trans = *it;
      CE_UNSET(trans.Entity);
    }

  _transformations.clear();
}

ceMatrix4f& ceTransformer::GetTransformation ()
{
  return _transformation;
}

void ceTransformer::AddNode(ceNode *node)
{
  if (!node)
    {
      return;
    }

  switch (node->GetNodeType())
    {
    case NT_EntityNode:
      {
        Trans trans;
        trans.Entity = static_cast<ceEntityNode*>(node);
        trans.OriginMatrix = trans.Entity->GetMatrix();
        trans.Entity->AddRef();
        _transformations.push_back(trans);
      }
      break;


    case NT_LODNode:
      {
        ceLODNode* lodNode = static_cast<ceLODNode*>(node);
        ceLevelOfDetail<ceNode>& lod = lodNode->Get();
        for (unsigned i=0; i<lod.GetNumberOfLevels(); ++i)
          {
            AddNode (lod.Get(i));
          }
      }
      break;

    default:
      break;
    }
}

void ceTransformer::RemoveTrans(ceEntityNode *node)
{
  std::vector<Trans>::iterator it;
  for (it = _transformations.begin();
       it != _transformations.end();
       ++it)
    {
      Trans& tr = *it;

      if (tr.Entity == node)
        {
          _transformations.erase(it);
          return;
        }
    }
}

void ceTransformer::RemoveNode(ceNode *node)
{
  if (!node)
    {
      return;
    }

  switch (node->GetNodeType())
    {
    case NT_EntityNode:
      {
        RemoveTrans(static_cast<ceEntityNode*>(node));
      }
      break;

    case NT_LODNode:
      {
        ceLODNode* lodNode = static_cast<ceLODNode*>(node);
        ceLevelOfDetail<ceNode>& lod = lodNode->Get();
        for (unsigned i=0; i<lod.GetNumberOfLevels(); ++i)
          {
            RemoveNode (lod.Get(i));
          }
      }
      break;

    default:
      break;
    }
}

void ceTransformer::Finish()
{
  _transformation.SetIdentity();
  if (_transformations.size() == 0)
    {
      return;
    }
  else if (_transformations.size() == 1)
    {
      _transformation = _transformations[0].OriginMatrix;
    }
  else
    {
      ceVector3f trans (0.0f, 0.0f, 0.0f);
      for (unsigned i=0, j=_transformations.size(); i<j; ++i)
        {
          ceMatrix4f& om = _transformations[i].OriginMatrix;
          trans += om.GetTranslation();
        }
      trans /= (float)_transformations.size();
      _transformation.SetTranslation(trans);
    }
  _transformationInv = _transformation.FastInverted();
}

void ceTransformer::UpdateTransformation()
{
  ceMatrix4f applyMatrix = _transformation * _transformationInv;
  for (unsigned i=0, j=_transformations.size(); i<j; ++i)
    {
      Trans& trans = _transformations[i];

      ceMatrix4f realTrans = applyMatrix * trans.OriginMatrix;
      trans.Entity->SetMatrix(realTrans);
      trans.Entity->FinishTransformation(true);
    }
}

void ceTransformer::ApplyTransformation()
{
  _transformationInv = _transformation.FastInverted();
  for (unsigned i=0, j=_transformations.size(); i<j; ++i)
    {
      Trans& trans = _transformations[i];
      trans.OriginMatrix = trans.Entity->GetMatrix();
    }
}

void ceTransformer::ResetTransformation()
{
  for (unsigned i=0, j=_transformations.size(); i<j; ++i)
    {
      Trans& trans = _transformations[i];
      trans.Entity->SetMatrix(trans.OriginMatrix);
      trans.Entity->FinishTransformation(true);
    }

  Finish ();
}

unsigned ceTransformer::GetNumberOfNodes() const
{
  return _transformations.size();
}

bool ceTransformer::IsValid() const
{
  return _transformations.size() > 0;
}
